package com.wfs.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;

/**
 * 直接用map接收数据
 *
 * @author Jiaju Zhuang
 */
public class NoModelDataListener extends AnalysisEventListener<Map<Integer, String>> {
    private static final Logger LOGGER = LoggerFactory.getLogger(NoModelDataListener.class);
    /**
     * 每隔5条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 5;
    private  List<Map<Integer, String>> list = new ArrayList<Map<Integer, String>>();

    private Map<Integer, String> columnMap=new HashMap<>();
    //基础配置列map
    private Map<String, String > basicMap=new HashMap<>();

    ExcelWriter excelWriter;
    WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").registerWriteHandler(ExcelStyleUtils.handlerStyleWrite()).build();
    static String  fileName="\\异常文件记录.xlsx";
    public NoModelDataListener(Map<String, String > basicMap) {
        this.basicMap=basicMap;
    }

    @Override
    public void invoke(Map<Integer, String> data, AnalysisContext context) {
       System.err.println("解析到一条数据:{}"+JSON.toJSONString(data));
        list.add(data);
        if (list.size() >= BATCH_COUNT) {
            saveData();
            list.clear();
        }
    }

    /**
     * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
     *
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) {
        LOGGER.error("解析失败，但是继续解析下一行:{}", exception.getMessage());
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
            LOGGER.error("第{}行，第{}列解析异常，数据为:{}", excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
        }
    }



    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        ReadRowHolder readRowHolder = context.readRowHolder();
        Integer rowIndex = readRowHolder.getRowIndex();
       System.err.println("所有数据解析完成！");
        // 千万别忘记finish 会帮忙关闭流
        if (excelWriter != null) {
            excelWriter.finish();
        }
    }
    /**
     * 这里会一行行的返回头
     *
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
        this.columnMap=headMap;

        File file = new File(fileName);
        if (file.exists()){
            file.delete();
        }
        excelWriter= EasyExcel.write(fileName).head(head(columnMap)).build();
        System.err.println("解析到一条头数据:{}"+JSON.toJSONString(headMap));
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
       System.err.println("{}条数据，开始存储数据库！"+list.size());
        List<SendBillsVO> sendBills=new ArrayList<>();
        for (Map<Integer, String> integerStringMap : list) {
            SendBillsVO sendBill=new SendBillsVO();
            for (Map.Entry<Integer, String> entry : integerStringMap.entrySet()) {
                Integer key = entry.getKey();
                //获取列名
                String columName = columnMap.get(key);
                //获取对应编码
                String s = basicMap.get(columName);
                //如果元数据列不为空则进行操作 否则不做处理
                if (Objects.nonNull(s)){
                    //如果为系统自定义 或者作为查询的 则放到数据库字段
                    setValue(s,entry.getValue(),sendBill);
                }
            }
            try {
                BigDecimal.valueOf(Double.valueOf(sendBill.getWeight()));
                sendBills.add(sendBill);
                // 这里 需要指定写用哪个class去写
                    // 这里注意 如果同一个sheet只要创建一次

                    // 去调用写入,这里我调用了五次，实际使用时根据数据库分页的总的页数来
                    //excelWriter.write(data(integerStringMap), writeSheet);
                    //excelWriter.write(data(integerStringMap), writeSheet);
                    //WriteSheet build = writerSheetBuilder.build();
                    excelWriter.write(data(integerStringMap), writeSheet);
                    excelWriter.write(data(integerStringMap), writeSheet);

            }catch (Exception e){
                e.printStackTrace();
            }
        }
       System.err.println("存储数据库成功！");
    }


    /**
     * 反射赋值
     */
    private void setValue(String fieldName,String value ,SendBillsVO sendBill){
        String methodName="set"+fieldName.substring(0,1).toUpperCase()+
                fieldName.substring(1);
        Method method2 ;
        try {
            method2 = sendBill.getClass().getMethod(methodName,String.class);
            method2.invoke(sendBill,value);
        } catch (Exception e) {
            if (e instanceof NoSuchMethodException  ){
                e.printStackTrace();
            }
        }
    }

    private List<List<String>> head(Map<Integer, String> headMap) {
        List<List<String>> lists=new ArrayList<>();
        for (Map.Entry<Integer, String> integerStringEntry : headMap.entrySet()) {
            List<String> list=new ArrayList<>();
            list.add(integerStringEntry.getValue());
            lists.add(integerStringEntry.getKey(),list);
        }
        return lists;
    }

    private   List<List<String>> data() {
        List<List<String>> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            List<String> list1=new ArrayList<>();
            String data ="字符串" + i;
            list1.add(data);
            list.add(list1);
        }

        return list;
    }
    private List data(Map<Integer, String> integerStringMap) {
        List<List<String>> lists = new ArrayList<>();
        List<String> array=new ArrayList<>();
        for (Map.Entry<Integer, String> entry : integerStringMap.entrySet()) {
            array.add(entry.getKey(),entry.getValue());
        }
        lists.add(array);
        return lists;
    }

}
